Base IModule
Overview
The Core Module Interface (IModule) serves as the foundation for all module types in the ERC-7579 smart account system. All specialized modules (Validator, Executor, Hook, Fallback) must implement this base interface.
Interface Definition
interface IModule {
error AlreadyInitialized(address smartAccount);
error NotInitialized(address smartAccount);
function onInstall(bytes calldata data) external;
function onUninstall(bytes calldata data) external;
function isModuleType(uint256 moduleTypeId) external view returns (bool);
function isInitialized(address smartAccount) external view returns (bool);
}
Core Functions
onInstall
Called when installing the module on a smart account.
function onInstall(bytes calldata data) external;
- Must revert if module is already initialized
- Handles initialization logic using provided data
- Typically sets up initial state for the account
onUninstall
Called when removing the module from a smart account.
function onUninstall(bytes calldata data) external;
- Must revert if module is not initialized
- Handles cleanup and state removal
- Ensures proper module deactivation
isModuleType
Verifies if the module matches a specific type.
function isModuleType(uint256 moduleTypeId) external view returns (bool);
- Returns true if module matches the specified type
- Module types are defined as constants:
MODULE_TYPE_VALIDATOR = 1MODULE_TYPE_EXECUTOR = 2MODULE_TYPE_FALLBACK = 3MODULE_TYPE_HOOK = 4
isInitialized
Checks if the module is initialized for a specific account.
function isInitialized(address smartAccount) external view returns (bool);
- Returns true if module is active for the account
- Used for validation before operations
Implementation Example
abstract contract BaseModule is IModule {
// Tracks initialized accounts
mapping(address => bool) internal initializedAccounts;
function onInstall(bytes calldata data) external virtual {
if (initializedAccounts[msg.sender]) {
revert AlreadyInitialized(msg.sender);
}
initializedAccounts[msg.sender] = true;
// Additional initialization logic
}
function onUninstall(bytes calldata data) external virtual {
if (!initializedAccounts[msg.sender]) {
revert NotInitialized(msg.sender);
}
initializedAccounts[msg.sender] = false;
// Additional cleanup logic
}
function isInitialized(address smartAccount) public view virtual returns (bool) {
return initializedAccounts[smartAccount];
}
}
Best Practices
-
State Management
- Use clear state variables for initialization tracking
- Implement proper access control
- Handle state changes atomically
-
Error Handling
- Use custom errors for better gas efficiency
- Include descriptive error messages
- Validate all inputs
-
Gas Optimization
- Use mappings for O(1) lookups
- Minimize storage operations
- Batch operations when possible
Security Considerations
-
Access Control
- Only allow authorized accounts to install/uninstall
- Validate caller permissions
- Implement proper initialization checks
-
State Consistency
- Ensure atomic state changes
- Prevent reentrant calls
- Validate state transitions
-
Upgrade Safety
- Plan for potential upgrades
- Maintain state consistency
- Document state variables